# -*- coding: utf-8 -*-
# @Time : 2022/5/10 10:44
# @FileName: AccurateCurveDialog.py
# @Mail: lizhigen1996@aliyun.com

__author__ = 'Zhigen.li'

from PyQt5.QtChart import QChart, QLineSeries, QValueAxis, QChartView, QDateTimeAxis
import datetime
import time
import sys, os
from PyQt5.QtCore import Qt, QRect, QDateTime, QDate, QPoint, QPointF, pyqtSignal, QEvent
from PyQt5.QtGui import QPainter, QCursor, QColor, QBrush, QMouseEvent, QIcon
from PyQt5.QtWidgets import QToolTip, QWidget, QApplication, QGridLayout, QGraphicsSimpleTextItem, \
                            QPushButton, QSpacerItem, QSizePolicy, QMenu, QAction, QDialog
from res.resource_rc import *
from Config.Config import CatchExceptions

class MyChartView(QChartView):
    mouseMoving = pyqtSignal(QPointF)

    def __init__(self, chart, timeList, data):
        super(MyChartView, self).__init__(chart)
        self.timeList = timeList
        self.data = data
        self.m_coordItem = None
        self.mouseMoving.connect(self.onMouseMoving)

        self.serie_pointX = QLineSeries(self.chart())
        self.serie_pointY = QLineSeries(self.chart())
        self.serie_pointX.setName('PointX')
        self.serie_pointY.setName('PointY')
        self.serie_pointX.setVisible(False)
        self.serie_pointY.setVisible(False)
        self.chart().addSeries(self.serie_pointX)
        self.chart().addSeries(self.serie_pointY)

    def setAxis(self, axisX, axisY):
        self.axisX = axisX
        self.axisY = axisY
        self.chart().setAxisX(axisX, self.serie_pointX)
        self.chart().setAxisY(axisY, self.serie_pointX)
        self.chart().setAxisX(axisX, self.serie_pointY)
        self.chart().setAxisY(axisY, self.serie_pointY)

    @CatchExceptions
    def mouseMoveEvent(self, event: QMouseEvent):
        if not self.m_coordItem:
            self.m_coordItem = QGraphicsSimpleTextItem(self.chart())
            self.m_coordItem.setZValue(5)
            self.m_coordItem.show()

        self.m_coordItem.setVisible(False)
        curPos = event.pos()
        curVal = self.chart().mapToValue(curPos)
        timeArr = time.localtime(curVal.x() // 1000)
        timeStr = time.strftime("%H:%M", timeArr)

        # 时间并不是连续的
        num = 6 * 60  # 最多15次
        idx = -1
        while num > 0:
            try:
                idx = self.timeList.index(timeStr)
                break
            except:
                t = datetime.datetime.strptime(timeStr, "%H:%M") - datetime.timedelta(minutes=1)
                timeStr = t.strftime("%H:%M")
            num -= 1

        if idx < 0:
            return super(MyChartView, self).mouseMoveEvent(event)

        text = '时间：{}\n'.format(self.timeList[idx])
        s = '预估净值：{}%'.format(self.data[idx])
        text += s

        self.m_coordItem.setText(text)
        self.m_coordItem.setPos(curPos.x(), curPos.y())

        self.m_coordItem.setVisible(True)
        self.mouseMoving.emit(curVal)

        # 隐藏部分图例
        for mark in self.chart().legend().markers():
            if 'Point' in mark.label().title():
                mark.setVisible(False)

        return super(MyChartView, self).mouseMoveEvent(event)

    @CatchExceptions
    def onMouseMoving(self, point: QPointF):
        self.serie_pointX.clear()
        self.serie_pointY.clear()

        self.serie_pointX.append(QPointF(self.axisX.min().toMSecsSinceEpoch(), point.y()))
        self.serie_pointX.append(QPointF(self.axisX.max().toMSecsSinceEpoch(), point.y()))
        self.serie_pointY.append(QPointF(point.x(), self.axisY.min()))
        self.serie_pointY.append(QPointF(point.x(), self.axisY.max()))
        self.serie_pointX.setVisible(True)
        self.serie_pointY.setVisible(True)

    def leaveEvent(self, a0: QEvent):
        self.serie_pointX.setVisible(False)
        self.serie_pointY.setVisible(False)
        self.m_coordItem.setVisible(False)


class AccurateCurveDialog(QDialog):
    def __init__(self):
        super(AccurateCurveDialog, self).__init__()
        self.resize(880, 300)
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName("gridLayout")
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.timeList = []
        self.dataList = []
        self.name = ''

    @CatchExceptions
    def showPlot(self, name):
        self.name = name
        path = r'C:\Config\{}.csv'.format(datetime.datetime.now().strftime('%Y%m%d'))
        try:
            if os.path.exists(path):
                with open(path, 'r') as fp:
                    csvData = fp.read()
            else:
                raise Exception('未找到净值估算数据!')

            if csvData and csvData != '':
                csvLines = csvData.split('\n')
                for csvLine in csvLines:
                    cells = csvLine.split(',')
                    if name == cells[0]:
                        for idx, cell in enumerate(cells):
                            if idx == 0:
                                continue
                            if idx % 2 == 0:
                                self.dataList.append(round(float(cell), 2))
                                t = cells[idx - 1]
                                tDate = datetime.datetime.strptime(t, '%H:%M')
                                if tDate < datetime.datetime.strptime('09:20', '%H:%M'):
                                    self.dataList.pop(-1)
                                    self.timeList.pop(-1)
                            else:
                                self.timeList.append(cell)
                        break


            else:
                raise Exception('净值估算数据为空!')
        except Exception as e:
            raise Exception('未找到净值估算数据! {}'.format(str(e)))

        if len(self.dataList) != len(self.timeList):
            raise Exception('净值估算数据格式错误!')
        if len(self.dataList) < 1:
            raise Exception('净值估算数据过少，暂不展示，请稍后重试！')

        self.create_chart()
        self.exec()

    @CatchExceptions
    def create_chart(self):
        self.setWindowTitle(self.name + '实时净值估算图')
        # 创建折线视图窗口
        chart = QChart()
        chart.setContentsMargins(0, 0, 0, 0)
        chart.setBackgroundBrush(QBrush(QColor("#FFFFFF")))     # 改变图背景色
        chart.setAnimationOptions(QChart.AllAnimations)

        #  图形项默认无法接收悬停事件，可以使用QGraphicsItem的setAcceptHoverEvents()函数使图形项可以接收悬停事件。
        chart.setAcceptHoverEvents(True)

        # 执行创建折线的函数
        axisX, axisY = self.create_series(chart)
        chartView = MyChartView(chart, self.timeList, self.dataList)
        chartView.setContentsMargins(0, 0, 0, 0)
        chartView.setAxis(axisX, axisY)
        # self.gridLayout.addWidget(chartView, 1, 0, 1, 2)
        # self.gridLayout.setRowStretch(0, 1)
        # self.gridLayout.setRowStretch(1, 15)
        self.gridLayout.addWidget(chartView, 0, 0, 1, 1)
        chartView.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        chartView.raise_()

    @CatchExceptions
    def create_series(self, chart):
        # 坐标轴
        axisX = QDateTimeAxis()
        axisX.setFormat('hh:mm')
        axisX.setTitleText('时间')
        chart.addAxis(axisX, Qt.AlignBottom)
        axisY = QValueAxis()
        axisY.setLabelFormat('%.2f')
        axisY.setTitleText('估算净值')
        chart.addAxis(axisY, Qt.AlignLeft)

        # 创建曲线
        series = QLineSeries(chart)
        # 设置折线名
        series.setName(self.name)

        for idx, d in enumerate(self.dataList):
            t = self.timeList[idx]
            t = '2022/01/01 ' + t + ':00'
            t = datetime.datetime.strptime(t, '%Y/%m/%d %H:%M:%S')
            qtData = QDateTime(t.year, t.month, t.day, t.hour, t.minute, t.second)
            series.append(qtData.toMSecsSinceEpoch(), d)

        series.setPointsVisible(True)  # 显示圆点
        chart.addSeries(series)  # 添加折线到视图窗口
        chart.setAxisX(axisX, series)
        chart.setAxisY(axisY, series)

        return axisX, axisY


    def closeEvent(self, a0):
        super(AccurateCurveDialog, self).closeEvent(a0)
        del self

    def keyReleaseEvent(self, event):
        modi = event.modifiers()
        if (modi & Qt.ControlModifier):
            key = event.key()
            if key == Qt.Key_C:
                self.close()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    # 初始化所有视图
    login = AccurateCurveDialog()
    login.showPlot('招商中证白酒指数(LOF)A')
    login.exec()
    sys.exit(app.exec_())